//md5 2b3f15d93690a862f85dc248c3870757
(function() {
  var _, _expr, _importLib, all0, all1, bin, cat, chdl_base, dec, expand, has0, has1, hasEven1, hasOdd1, hex, infer, mem_mux, oct;

  chdl_base = require('chdl_base');

  ({_expr} = require('chdl_utils'));

  ({cat, expand, all1, all0, has0, has1, hasOdd1, hasEven1} = require('chdl_operator'));

  ({infer, hex, oct, bin, dec} = require('chdl_base'));

  ({_importLib} = require('chdl_transpiler_engine'));

  module.paths.push('/home/lisiyu/work/project/fft/src');

  _ = require('lodash');

  mem_mux = class mem_mux extends chdl_base.Module {
    constructor(req_num, mem_bank, mem_data_width, mem_depth, strategy) {
      super();
      this._mixin(_importLib('chdl_component_lib.chdl', __dirname));
      this.req_num = req_num != null ? req_num : 2;
      this.mem_bank = mem_bank != null ? mem_bank : 2;
      this.mem_data_width = mem_data_width != null ? mem_data_width : 32;
      this.mem_depth = mem_depth != null ? mem_depth : 128;
      this.req_addr_width = 32;
      this.mem_addr_width = 32;
      this.strategy = strategy != null ? strategy : "round"; // “fix ” or "round"
      this._port({
        mem_req: this.createArray(this.req_num, () => {
          return {
            valid: chdl_base.input(1),
            ready: chdl_base.output(1),
            we_n: chdl_base.input(1),
            addr: chdl_base.input(this.req_addr_width),
            rdata: chdl_base.output(this.mem_data_width),
            wdata: chdl_base.input(this.mem_data_width)
          };
        }),
        mem: this.createArray(this.mem_bank, () => {
          return {
            ce_n: chdl_base.output(),
            we_n: chdl_base.output(),
            addr: chdl_base.output(this.mem_addr_width),
            rdata: chdl_base.input(this.mem_data_width),
            wdata: chdl_base.output(this.mem_data_width)
          };
        })
      });
    }

    build() {
      var addr_list, addr_t, bank, bank_list, ce_n_list, i, idx, j, k, l, len, len1, len2, len3, len4, len5, len6, len7, len8, len9, m, mem, mem_addr_t, mem_sel, mux2req, n, o, p, q, r, rdata_list, ready_list, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, req_idx, results, t, wdata_list, we_n_list;
      mem_sel = this.createArray(this.mem_bank, () => {
        return {
          ce: this.createArray(this.mem_bank, () => {
            return this._localWire(1, "mem_sel");
          }),
          idx: this._localWire(this.numWidth(this.mem_bank), "mem_sel_idx"),
          idx_dly: this._localReg(this.numWidth(this.mem_bank), "mem_sel_idx_dly")
        };
      });
      mux2req = this.createArray(this.req_num, () => {
        return {
          ready_dly: this._localReg(1, "mux2req_ready_dly"),
          ready: this._localWire(1, "mux2req_ready")
        };
      });
      mem = this.createArray(this.mem_bank, () => {
        return {
          start_addr: 0,
          end_addr: 0
        };
      });
      ref = _.range(this.mem_bank);
      for (i = 0, len = ref.length; i < len; i++) {
        bank = ref[i];
        mem[bank].start_addr = bank * this.mem_depth;
        mem[bank].end_addr = bank * this.mem_depth + this.mem_depth - 1;
      }
      bank_list = [];
      ref1 = _.range(this.mem_bank);
      for (j = 0, len1 = ref1.length; j < len1; j++) {
        bank = ref1[j];
        ref2 = _.range(this.req_num);
        for (k = 0, len2 = ref2.length; k < len2; k++) {
          req_idx = ref2[k];
          t = this._localWire(1, "t");
          this._assign(t, '64')(() => {
            return _expr(chdl_base.Expr.start().next(this._inRange(this.mem_req[req_idx].addr, mem[bank].start_addr, mem[bank].end_addr, true, false)), '64');
          });
          this._assign(mem_sel[bank].ce[req_idx], '65')(() => {
            return this._if(chdl_base.Expr.start().next(t), '66')(() => {
              return _expr(chdl_base.Expr.start().next(this.mem_req[req_idx].valid), '67');
            })._else('68')(() => {
              return _expr(chdl_base.Expr.start().next(bin(1, 0)), '69');
            })._endif();
          });
        }
      }
      //bank_list.push(ce_list)
      if (this.strategy === "fix") {
        for (idx = l = 0, len3 = mem_sel.length; l < len3; idx = ++l) {
          bank = mem_sel[idx];
          this._assign(mem_sel[idx].idx, '75')(() => {
            return _expr(chdl_base.Expr.start().next(this._fix_arbiter(bank.ce, this.mem_bank)), '75');
          });
          this._assign(mem_sel[idx].idx_dly, '76')(() => {
            return _expr(chdl_base.Expr.start().next(mem_sel[idx].idx), '76');
          });
        }
      } else {
        for (idx = m = 0, len4 = mem_sel.length; m < len4; idx = ++m) {
          bank = mem_sel[idx];
          this._assign(mem_sel[idx].idx, '80')(() => {
            return _expr(chdl_base.Expr.start().next(this._round_arbiter(bank.ce, bin(1, 1), this.mem_bank)), '80');
          });
          this._assign(mem_sel[idx].idx_dly, '81')(() => {
            return _expr(chdl_base.Expr.start().next(mem_sel[idx].idx), '81');
          });
        }
      }
      ref3 = _.range(this.req_num);
      for (n = 0, len5 = ref3.length; n < len5; n++) {
        idx = ref3[n];
        ready_list = [];
        rdata_list = [];
        ref4 = _.range(this.mem_bank);
        for (o = 0, len6 = ref4.length; o < len6; o++) {
          bank = ref4[o];
          ready_list.push(this._cond(chdl_base.Expr.start().next(mem_sel[bank].idx).next("==").next(idx), '86')(() => {
            return _expr(chdl_base.Expr.start().next(bin(1, 1)), '86');
          }));
          rdata_list.push(this._cond(chdl_base.Expr.start().next(mem_sel[bank].idx_dly).next("==").next(idx), '87')(() => {
            return _expr(chdl_base.Expr.start().next(this.mem[bank].rdata), '87');
          }));
        }
        ready_list.push(this._cond(null, '88')(() => {
          return _expr(chdl_base.Expr.start().next(dec(0)), '88');
        }));
        this._assign(mux2req[idx].ready, '89')(() => {
          return _expr(chdl_base.Expr.start().next(this._order(ready_list, bin(1, 0))), '89');
        });
        this._assign(this.mem_req[idx].rdata, '90')(() => {
          return _expr(chdl_base.Expr.start().next(this._balance(rdata_list, this.mem_data_width)), '90');
        });
      }
      ref5 = _.range(this.req_num);
      for (p = 0, len7 = ref5.length; p < len7; p++) {
        idx = ref5[p];
        this._assign(mux2req[idx].ready_dly, '93')(() => {
          return _expr(chdl_base.Expr.start().next(mux2req[idx].ready), '93');
        });
        this._assign(this.mem_req[idx].ready, '94')(() => {
          return _expr(chdl_base.Expr.start().next(mux2req[idx].ready), '94');
        });
      }
      ref6 = _.range(this.mem_bank);
      //$if(@mem_req[idx].we_n && @mem_req[idx].valid)
      //  $ mux2req[idx].ready_dly
      //$else
      //  $ mux2req[idx].ready
      results = [];
      for (q = 0, len8 = ref6.length; q < len8; q++) {
        bank = ref6[q];
        we_n_list = [];
        wdata_list = [];
        addr_list = [];
        ce_n_list = [];
        ref7 = _.range(this.req_num);
        for (r = 0, len9 = ref7.length; r < len9; r++) {
          idx = ref7[r];
          we_n_list.push(this._cond(chdl_base.Expr.start().next("(").next(mem_sel[bank].idx).next("==").next(idx).next(")").next("&&").next(mem_sel[bank].ce[idx]), '106')(() => {
            return _expr(chdl_base.Expr.start().next(this.mem_req[idx].we_n), '106');
          }));
          ce_n_list.push(this._cond(chdl_base.Expr.start().next("(").next(mem_sel[bank].idx).next("==").next(idx).next(")").next("&&").next(mem_sel[bank].ce[idx]), '107')(() => {
            return _expr(chdl_base.Expr.start().next("(").next("!").next(this.mem_req[idx].valid).next(")"), '107');
          }));
          wdata_list.push(this._cond(chdl_base.Expr.start().next("(").next(mem_sel[bank].idx).next("==").next(idx).next(")").next("&&").next(mem_sel[bank].ce[idx]), '108')(() => {
            return _expr(chdl_base.Expr.start().next(this.mem_req[idx].wdata), '108');
          }));
          addr_list.push(this._cond(chdl_base.Expr.start().next("(").next(mem_sel[bank].idx).next("==").next(idx).next(")").next("&&").next(mem_sel[bank].ce[idx]), '109')(() => {
            return _expr(chdl_base.Expr.start().next("(").next(this.mem_req[idx].addr).next(")"), '109');
          }));
        }
        ce_n_list.push(this._cond(chdl_base.Expr.start().next("null"), '110')(() => {
          return _expr(chdl_base.Expr.start().next(bin(1, 1)), '110');
        }));
        addr_t = this._localWire(this.req_addr_width, "addr_t");
        this._assign(addr_t, '111')(() => {
          return _expr(chdl_base.Expr.start().next(this._balance(addr_list, this.req_addr_width)), '111');
        });
        mem_addr_t = this._localWire(this.req_addr_width, "mem_addr_t");
        this._assign(mem_addr_t, '112')(() => {
          return _expr(chdl_base.Expr.start().next(addr_t).next("-").next(mem[bank].start_addr), '112');
        });
        this._assign(this.mem[bank].addr, '113')(() => {
          return _expr(chdl_base.Expr.start().next(mem_addr_t(0, this.mem_addr_width)), '113');
        });
        this._assign(this.mem[bank].wdata, '114')(() => {
          return _expr(chdl_base.Expr.start().next(this._balance(wdata_list, this.mem_data_width)), '114');
        });
        this._assign(this.mem[bank].we_n, '115')(() => {
          return _expr(chdl_base.Expr.start().next(this._balance(we_n_list, 1)), '115');
        });
        results.push(this._assign(this.mem[bank].ce_n, '116')(() => {
          return _expr(chdl_base.Expr.start().next(this._order(ce_n_list)), '116');
        }));
      }
      return results;
    }

  };

  module.exports = mem_mux;

  return module.exports;

}).call(this);
